home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Dialogs / DraftWn.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  47.2 KB  |  1,688 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DraftWn.cpp
  3.  
  4.     Contains:    Implementation of the DraftWin and DraftInfoRec classes
  5.  
  6.     Owned by:    Eric House
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <10>     9/27/96    EL        1353486: document may become write
  13.                                     protected after opening.
  14.          <9>    20.09.1996    NP        1386083: Add include
  15.          <8>     9/12/96    eeh        1386008: weak link against appleguidelib
  16.          <7>     9/11/96    eeh        1386008: AG fix for 68K
  17.          <6>     9/10/96    eeh        1386008: AppleGuide support (incomplete)
  18.          <5>      9/4/96    EL        1306385: Remove user item that are used as
  19.                                     default button in dialog.
  20.          <4>      7/8/96    eeh        undo task 10008 (AppleGuide buttons)
  21.          <3>     6/21/96    eeh        task 10008: add buttons etc. for AppleGuide
  22.          <2>     6/21/96    RA        T10025: Call InitBndNSUtils
  23.          <0>     6/7/96    eeh        first checked in (moved from ::DocShell:)
  24.  
  25.     To Do:
  26.     In Progress:
  27.         
  28. */
  29.  
  30.  
  31. #ifndef _DRAFTWLD_
  32. #include "DraftWLD.h"
  33. #endif
  34.  
  35. #ifndef SOM_Module_OpenDoc_StdProps_defined
  36. #include <StdProps.xh>
  37. #endif
  38.  
  39. #ifndef _DRAFTWN_
  40. #include "DraftWn.h"
  41. #endif
  42.  
  43. #ifndef _TEMPOBJ_
  44. #include "TempObj.h"
  45. #endif
  46.  
  47. #ifndef _USERSRCM_
  48. #include <UseRsrcM.h>
  49. #endif
  50.  
  51. #ifndef _AGSUPPORT_
  52. #include "AGSupprt.h"
  53. #endif
  54.  
  55. #ifndef SOM_ODDocument_xh
  56. #include <Document.xh>
  57. #endif
  58.  
  59. #ifndef SOM_ODContainer_xh
  60. #include <ODCtr.xh>
  61. #endif
  62.  
  63. #ifndef _ODUTILS_
  64. #include <ODUtils.h>
  65. #endif
  66.  
  67. #ifndef SOM_ODWindowState_xh
  68. #include <WinStat.xh>
  69. #endif
  70.  
  71. #ifndef SOM_ODWindowIterator_xh
  72. #include <WinIter.xh>
  73. #endif
  74.  
  75. #ifndef SOM_ODWindow_xh
  76. #include <Window.xh>
  77. #endif
  78.  
  79. #ifndef _DOCUTILS_
  80. #include <DocUtils.h>
  81. #endif
  82.  
  83. #ifndef SOM_ODStorageUnit_xh
  84. #include <StorageU.xh>
  85. #endif
  86.  
  87. #ifndef SOM_ODClipboard_xh
  88. #include <Clipbd.xh>
  89. #endif
  90.  
  91. #ifndef SOM_ODStorageUnitView_xh
  92. #include <SUView.xh>
  93. #endif
  94.  
  95. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  96. #include <StdTypes.xh>
  97. #endif
  98.  
  99. #ifndef _ODMEMORY_
  100. #include <ODMemory.h>
  101. #endif
  102.  
  103. #ifndef _PLFMFILE_
  104. #include <PlfmFile.h>
  105. #endif
  106.  
  107. #ifndef _DLOGUTIL_
  108. #include <DlogUtil.h>
  109. #endif
  110.  
  111. #ifndef _STORUTIL_
  112. #include <StorUtil.h>
  113. #endif
  114.  
  115. #ifdef _APPLEGUIDE_READY_
  116. #ifndef __APPLEGUIDE__
  117. #include <AppleGuide.h>
  118. #endif
  119. #endif
  120.  
  121. #ifndef __TIME_H__
  122. #include <Time.h>
  123. #endif
  124.  
  125. #ifndef _PASCLSTR_
  126. #include <PasclStr.h>
  127. #endif
  128.  
  129. #ifndef _ISOSTR_
  130. #include <ISOStr.h>
  131. #endif
  132.  
  133. #ifndef _ITEXT_
  134. #include <IText.h>
  135. #endif
  136.  
  137. #ifndef __SCRIPT__
  138. #include <script.h>
  139. #endif
  140.  
  141. #ifndef __DIALOGS__
  142. #include <Dialogs.h>
  143. #endif
  144.  
  145. #ifndef __LISTS__
  146. #include <Lists.h>
  147. #endif
  148.  
  149. #ifndef __TOOLUTILS__
  150. #include <ToolUtils.h>
  151. #endif
  152.  
  153. #ifndef __RESOURCES__
  154. #include <Resources.h>
  155. #endif
  156.  
  157. #ifdef __SC__
  158. #ifndef __PACKAGES__
  159. #include <Packages.h>
  160. #endif
  161. #else
  162. #ifndef __TEXTUTILS__
  163. #include <TextUtils.h>
  164. #endif
  165. #endif
  166.  
  167. #ifndef __ICONS__
  168. #include <Icons.h>
  169. #endif
  170.  
  171. #ifndef _ODMEMORY_
  172. #include <ODMemory.h>
  173. #endif
  174.  
  175. #ifndef SOM_ODSession_xh
  176. #include <ODSessn.xh>
  177. #endif
  178.  
  179. #ifndef _STDTYPIO_
  180. #include <StdTypIO.h>
  181. #endif
  182.  
  183. #ifndef _STORUTIL_
  184. #include <StorUtil.h>
  185. #endif
  186.  
  187. #ifndef _BNDNSUTL_
  188. #include "BndNSUtl.h"
  189. #endif
  190.  
  191. #ifndef _MISCUTIL_
  192. #include "MiscUtil.h"
  193. #endif
  194.  
  195. #pragma segment DraftWindow
  196.  
  197. //==============================================================================
  198. // Constants
  199. //==============================================================================
  200.  
  201. #define tenPt            10
  202. #define kNoExpandClick    -1
  203. #define kNoRowHilited    -1
  204.  
  205.  
  206. #define no_ictb_exists        false    /* try using an ictb resource instead of code */
  207.  
  208. #define kXMPNewLineChar    '\n'
  209.  
  210. #define    kDraftsActiveControl 0
  211.  
  212. // macros for passing info about default button behavior.  Currently involves
  213. // setting the low-order bit in the listhandle, which on the mac *should*
  214. // always be clear.  A cleaner implementation might be advised....
  215.  
  216. #define CREATEISSET(self)    (((DraftWindow*)(self))->CreateIsSet())
  217. #define GETLISTHANDLE(self)    (((DraftWindow*)(self))->GetListHandle())
  218. #define GETLISTRECT(self, rectPtr)                                            \
  219.         (((DraftWindow*)(self))->GetListRect((rectPtr)))
  220. #define SETREADYTOCLOSE(self)                                                \
  221.         (((DraftWindow*)(self))->SetReadyToClose(kODTrue))
  222. #define CLEARREADYTOCLOSE(self)                                                \
  223.         (((DraftWindow*)(self))->SetReadyToClose(kODFalse))
  224. #define READYTOCLOSESET(self)                                                \
  225.         (((DraftWindow*)(self))->ReadyToClose())
  226. #define kNumColumns 4
  227. #define    kCommentsColumnIndex 3
  228.  
  229. const short kControlActive = 0;
  230.  
  231. //==============================================================================
  232. // Scalar Types
  233. //==============================================================================
  234.  
  235. //==============================================================================
  236. // Local Classes
  237. //==============================================================================
  238.  
  239. //==============================================================================
  240. // Function Prototypes
  241. //==============================================================================
  242.  
  243. static void DrawDWUserStrings( struct DraftLDEFCallbackInfo *callbackInfo,
  244.         ODSShort row, const Rect* listItemRect );
  245. static DraftInfoRec* GetNthRow( DraftInfoRec* from, short whichRow );
  246. static void ContractList( FullDraftInfoRec* dir, ListHandle listH,    short parentRowNum );
  247. static void ExpandList( FullDraftInfoRec* dir, ListHandle listH, DialogPtr dialog,
  248.         short parentRowNum );
  249. static void AddRows( ListHandle listH, short startIndex, short numToAdd );
  250. static FullDraftInfoRec* FirstSelectedRow( DraftInfoRec* from );
  251. static TEHandle ITextToTERec( ODIText* iText, Rect* bothRects );
  252. static pascal void DrawListItem(DialogPtr dlog, short theItem);
  253. static pascal ODBoolean CheckDeleteKeyFilterProc( DialogPtr dialog, EventRecord *event,
  254.         short *itemHit);
  255. static pascal ODBoolean CheckKeyScriptFirstFilterProc( DialogPtr dialog, EventRecord *event,
  256.         short *itemHit);
  257. static pascal ODBoolean DraftDlgFilterProc( DialogPtr dialog, EventRecord *event,
  258.         short *itemHit );
  259. static void SetButtonStates( DialogPtr dlog, ODBoolean hasWriteAccess,
  260.         Boolean hasContent );
  261. static void SetRows( DraftInfoRec* dir,    short startRow, ODBoolean newValue,
  262.         ListHandle listH );
  263.  
  264. #ifdef __cplusplus
  265. extern "C" {
  266. #endif
  267. ODError DraftWindowEntry( Environment* ev, ODSession* session,
  268.         ODWindowState* winState, ODDocument* document );
  269. #ifdef __cplusplus
  270.     }
  271. #endif
  272.  
  273. //==============================================================================
  274. // Entry point: 
  275. //==============================================================================
  276.  
  277. ODError DraftWindowEntry( Environment* ev, ODSession* session,
  278.         ODWindowState* winState, ODDocument* document )
  279. {
  280.     ODError result = noErr;
  281.     TRY
  282.  
  283.         InitBindingNamespaceUtils(session);
  284.     
  285.         ODDraft* topDraft = ODGetTempDraftFromOpenDocument(ev, session, document);
  286.         if (topDraft)
  287.             topDraft->Acquire(ev);
  288.         else
  289.             topDraft = document->AcquireDraft(ev,kODDPReadOnly,0,kODNULL,kODPosTop,kODFalse);
  290.         
  291.         DraftWindow* d = new DraftWindow;
  292.         DraftWinAction     dWinAction = kDraftWinNone;
  293.         ODDraft*    curDraft = kODNULL;
  294.         d->InitDraftWindow(ev, topDraft);
  295.  
  296.         winState->DeactivateFrontWindows(ev);
  297.         ArrowCursor();
  298.         do {
  299.             PlatformFile* file = GetPlatformFileFromContainer(ev, document->GetContainer(ev));
  300.             ODBoolean isLocked = file->IsLocked();
  301.  
  302.             dWinAction = d->Drafts(ev, curDraft, dWinAction, ODDraftHasWriteAccess(ev, topDraft) && !isLocked);
  303.             switch (dWinAction) {
  304.                 case kDraftWinCreate:
  305.                     WASSERT(ODDraftHasWriteAccess(ev, topDraft));
  306.                     winState->ActivateFrontWindows(ev);
  307.                     d->DraftSaved(ev, topDraft);
  308.                     ODSaveDocument(ev, session, document);
  309.                     ODCloseDraft(ev, session, topDraft);
  310.     #ifdef ODDebug
  311.                     ODULong topDraftRefCount = topDraft->GetRefCount(ev);
  312.                     WASSERT(topDraftRefCount == 2);
  313.     #endif
  314.                     topDraft->Release(ev); // to balance the CreateDraft when the document was opened
  315.                     topDraft = document->CreateDraft(ev, topDraft, kODTrue);
  316.                         // This CreateDraft call is doing two things with refcounts.
  317.                         // First, it is releasing topDraft which balances the Acquire at the top of
  318.                         // this function.
  319.                         // Second, it is creating a new temp draft, which puts us in the same
  320.                         // state as we were before the above topDraft->Release, except
  321.                         // for the need to Reacquire the topDraft as was done at the top of this 
  322.                         // function which we do in the next statement.
  323.                     topDraft->Acquire(ev);
  324.                     
  325.                     ODTempDraftCreated(ev, session, document, topDraft);
  326.                     curDraft = topDraft;
  327.  
  328.                     {
  329.                     TempODStorageUnit su = topDraft->AcquireDraftProperties(ev);
  330.                     ODResetDateModByInfo(ev, su);    
  331.                     }
  332.                     
  333.                     d->InitDraftWindow(ev, topDraft);
  334.                     ODOpenDraft(ev, session, topDraft);
  335.                     ODSaveDocument(ev, session, document);
  336.                     winState->DeactivateFrontWindows(ev);
  337.                     
  338.                     break;
  339.                 case kDraftWinDelete:
  340.                     ODDraft* selDraft = d->GetSelectedDraft();
  341.  
  342.                     ODCloseDraft(ev, session, selDraft);
  343.                     ODReleaseObject( ev, selDraft );    // -- TÇ: was acquired in draftswindow
  344.  
  345.                     d->DeleteSelectedDraft(ev, session); 
  346.                     break;
  347.             }
  348.         } while (dWinAction == kDraftWinDelete);
  349.  
  350.         winState->ActivateFrontWindows(ev);
  351.         
  352.         if (dWinAction == kDraftWinOpen)
  353.         {
  354.             // open selected Drafts as additional root windows within this process
  355.             // if a particular draft already has a window, bring it to front, don't create a new one
  356.             ODDraft* selDraft = d->GetSelectedDraft();
  357.             WASSERT(selDraft);
  358.             
  359.             ODOpenDraft(ev, session, selDraft);
  360.         }
  361.         ODDeleteObject(d);
  362.         ODReleaseObject( ev, topDraft );    // balances Acquire & AcquireDraft at beginning.
  363.  
  364.         if ( dWinAction == kDraftWinLowMemAbort )
  365.             result = kODErrOutOfMemory;
  366.     CATCH_ALL
  367.         result = ErrorCode();
  368.     ENDTRY
  369.     return result;
  370. }
  371.  
  372. //==============================================================================
  373. // DraftWindow
  374. //==============================================================================
  375.  
  376. //------------------------------------------------------------------------------
  377. // Creation
  378. //------------------------------------------------------------------------------
  379.  
  380. DraftWindow::DraftWindow()
  381. {
  382.     fDraft        = kODNULL;
  383.     fDocument    = kODNULL;
  384.     fDraftInfo    = kODNULL;
  385.     fSelectedDraft = kODNULL;
  386.     fSelectedDraftNumber = 0;
  387. //    fExpandClickRow = kNoExpandClick;
  388. //    fHilitedRow = kODNULL;        // clear in Drafts() instead.
  389. }
  390.  
  391. void DraftWindow::InitDraftWindow(Environment* ev, ODDraft* draft)
  392. {    
  393.     fDraft         = draft;
  394.     fDocument    = draft->GetDocument(ev);
  395.     fListH        = kODNULL;
  396.     fCreateSet    = kODFalse;
  397.     fReadyToClose = kODFalse;
  398. }
  399.  
  400. //------------------------------------------------------------------------------
  401. // Destruction
  402. //------------------------------------------------------------------------------
  403.  
  404. DraftWindow::~DraftWindow()
  405. {            
  406.     ODReleaseObject(somGetGlobalEnvironment(),fSelectedDraft);
  407.     // dispose of DraftInfoRecs and collection
  408.     ODDeleteObject(fDraftInfo);
  409. }
  410.  
  411.  
  412. //------------------------------------------------------------------------------
  413. // Dialog
  414. //------------------------------------------------------------------------------
  415.  
  416. ListHandle DraftWindow::MakeAList(DialogPtr dlg, ODSShort* numLines,
  417.         long refcon )
  418. {
  419.     Rect        itemRect, boundsRect;
  420.     Handle        itemH;
  421.     short        scratchKind;
  422.  
  423.     /* create a scrolling list */
  424.  
  425.     GetDialogItem(dlg, kDraftsListUserItem, &scratchKind, &itemH, &itemRect);
  426.     itemRect.top -= 1;                                        
  427.     itemRect.left -= 1;                                        
  428.     SetRect(&boundsRect, 0, 0, 1, 0);                            /* one column list, 0 row count for now */
  429.  
  430.     FontInfo    scriptAppFontInfo;
  431.     GetFontInfo(&scriptAppFontInfo);
  432.     ODSShort cellHeight = scriptAppFontInfo.ascent +
  433.             scriptAppFontInfo.descent + scriptAppFontInfo.leading;
  434.     *numLines = (itemRect.bottom - itemRect.top) / cellHeight;
  435.  
  436.     fListRect = itemRect;
  437.     fListRect.bottom -= 1;
  438.     itemRect.right -= 15;
  439.     
  440.     InsetRect(&itemRect, 1, 1);                                    /* leave room for the frame */
  441.  
  442.     /* use the Application Font for the list items (cell size) */
  443.     long scriptAppFontSize = GetScriptVariable(smSystemScript,smScriptAppFondSize);
  444.     TextFont(HiWord(scriptAppFontSize));
  445.     TextSize(LoWord(scriptAppFontSize));        /* make look larger; icons will force this to be right once they're added */
  446.  
  447.     (LoWord(scriptAppFontSize) < tenPt) ? TextSize(tenPt) : TextSize(LoWord(scriptAppFontSize));
  448.  
  449.     Point cellSize;
  450.     SetPt(&cellSize, 500, cellHeight);
  451.     
  452.     /* now get the real desired font size */
  453.     long scriptSmallFontSize = GetScriptVariable(smSystemScript,smScriptSmallFondSize);
  454.     (LoWord(scriptSmallFontSize) < tenPt) ? TextSize(tenPt) : TextSize(LoWord(scriptSmallFontSize));
  455.  
  456.     Handle myHandle;
  457.     ListHandle listH;
  458.     { CUsingLibraryResources r;
  459.         myHandle = Get1Resource('LDEF',kDraftWinLDEFID);
  460.         THROW_IF_NULL(myHandle);
  461.         ListDefUPP LDEFUPP = NewListDefProc(DRAFTWINDOWLDEF);
  462.         (*(ListDefUPP*)&((*myHandle)[kDraftWinLDEFAddrOffset])) = LDEFUPP;
  463.         /* This above code written from suggestion in NIM:PPC System Software 1-35,1-36 */
  464.         
  465.         listH = LNew(&itemRect, &boundsRect, cellSize, kDraftWinLDEFID, dlg,
  466.                                         kODFalse, kODFalse, kODFalse, kODTrue);
  467.     }
  468.  
  469.     if (listH != nil)    
  470.     {                                            /* list was created */
  471.         (*listH)->refCon = refcon ;
  472.         /* resize list rectangle to only display whole cells */
  473.         itemRect.bottom -= (((short) (itemRect.bottom - itemRect.top)) % cellSize.v);
  474.         LSize(itemRect.right - itemRect.left, itemRect.bottom - itemRect.top, listH);
  475.         itemRect.right += 15;                /* add room for scroll bar */    
  476.         SetDialogItem(dlg, kDraftsListUserItem, scratchKind, itemH, &itemRect);
  477.     
  478. //        (*listH)->selFlags = lNoNilHilite;
  479. //        (*listH)->selFlags = (lOnlyOne | lNoNilHilite);
  480.         
  481.         LSetDrawingMode(kODFalse, listH);
  482.  
  483.         LDelRow(0, 0, listH);            /* delete everything in the list */
  484.         AddRows( listH, 0, this->CountDrafts() );
  485.  
  486.         LAutoScroll(listH);
  487.         LUpdate(dlg->visRgn, listH);
  488.         (*listH)->lastClick = *(Cell*)0L;
  489.         if ( fDraftInfo )
  490.             this->SetHilite( fDraftInfo, 0 );
  491. //        LSetDrawingMode(kODTrue, listH);
  492.     }
  493.     return listH;
  494. }    // DraftWindow::MakeAList
  495.  
  496. #if ODDebug
  497. void DraftWindow::CheckConsistency()
  498. {
  499.     if ( !fDraftInfo )
  500.         return;
  501.  
  502.     DraftInfoRec* dir = fDraftInfo;
  503.     short fullEntryCount = 0;
  504.     short dummyEntryCount = 0;
  505.     FullDraftInfoRec* fdir = kODNULL;
  506.     WASSERT( dir->GetComment() );
  507.     ODBoolean somethingExpanded = kODFalse;
  508.     ODBoolean foundHilite = kODFalse;
  509.     while ( dir )
  510.     {
  511.         if ( dir->GetDIRType() == kDIRTypeFull )
  512.         {
  513.             ++fullEntryCount;
  514.             fdir = (FullDraftInfoRec*)dir;
  515.             if ( fdir->ShouldHilite() )
  516.             {
  517.                 WASSERT( !foundHilite );
  518.                 foundHilite = kODTrue;
  519.             }
  520.             if ( fdir->IsExpanded() )
  521.             {
  522.                 somethingExpanded = kODTrue;
  523.                 WASSERT( fdir->GetCachedComment() != kODNULL );
  524.                 WASSERT( fdir->GetComment() != kODNULL );
  525.                 WASSERT( fdir->Next() != kODNULL );
  526.                 WASSERT( fdir->Next()->GetDIRType() != kDIRTypeFull );
  527.             }
  528.             else
  529.             {
  530.                 WASSERT( fdir->GetCachedComment() == kODNULL );
  531.                 WASSERT( fdir->GetComment() != kODNULL );
  532.             }
  533.         }
  534.         else
  535.         {
  536.             ++dummyEntryCount;
  537.             DummyDraftInfoRec* ddir = (DummyDraftInfoRec*)dir;
  538.             WASSERT( ddir->GetCommentOwner() );
  539.             WASSERT( ddir->GetCommentOwner() == fdir );
  540.             WASSERT( ddir->ShouldHilite() == fdir->ShouldHilite() );
  541.         }
  542.         dir = dir->Next();
  543.     }
  544.     if ( !somethingExpanded )
  545.         WASSERT( fullEntryCount == (*fListH)->dataBounds.bottom);
  546.     else
  547.         WASSERT( fullEntryCount+dummyEntryCount == (*fListH)->dataBounds.bottom);
  548.     WASSERT( foundHilite );
  549.     WASSERT( fullEntryCount == this->CountDrafts() );
  550. }
  551. #endif
  552.  
  553. DraftWinAction    DraftWindow::Drafts(Environment* ev, ODDraft* draft,
  554.         DraftWinAction prevAction, ODBoolean hasWriteAccess )
  555. {
  556.     // show the dialog/create the window and modally respond
  557.     // to events until dismissed
  558.     
  559.     short          itemKind,itemHit;
  560.     Rect        scratchRect;
  561.     Handle        scratchHandle;
  562.     
  563.     // worst case app heap memory usage between here and when the
  564.     // delete confirmation draft is up is 6448 bytes.  So I'm
  565.     // padding to 10000 to be safe.
  566.     // <eeh> need to reconsider now that comments expand?
  567.  
  568.     if ( !ODHaveFreeSpace( 10000, 0, kODTrue) )
  569.         return kDraftWinLowMemAbort;
  570.  
  571.     if ( draft != kODNULL )
  572.         fDraft = draft;        
  573.  
  574.     /// read and construct DraftInfo
  575.     fHilitedRow = kODNULL;        // clear this each time reopen dialog
  576.     fDraftInfo = this->InternalizeHistory(ev);
  577.  
  578.     GrafPort*    savePort;
  579.     GetPort(&savePort);
  580.  
  581.     TempODStorageUnit draftProps = fDraft->AcquireDraftProperties(ev);
  582.     ODSession *session = draftProps->GetSession(ev);
  583.     DialogPtr dlg;
  584.     {CUsingLibraryResources r;
  585.         dlg = ODGetNewDialog(ev,kDraftsDlgID,session,kODFalse);
  586.     }
  587.     THROW_IF_NULL(dlg);
  588.     SetPort(dlg);
  589.  
  590.     DialogSetUpAppleGuide( dlg, kDraftsAGButtonItem );
  591.  
  592.     PlatformFile* file = GetPlatformFileFromContainer(ev,
  593.             fDraft->GetDocument(ev)->GetContainer(ev));
  594.     Str255 dWinName;
  595.     ODName* fileName = file->GetName();
  596.     ODSLong savedRefNum;
  597.     BeginUsingLibraryResources(savedRefNum);
  598.     // DMc: ensure that string is deleted:
  599.     TempODString tempString = (char*) GetITextString(fileName, (StringPtr)kODNULL);
  600.     ConstStr255Param csp = (ConstStr255Param) (char*) tempString;
  601.     ReplaceIntoString( kDraftsWnTitleResID,
  602.             csp, kODNULL,
  603.             dWinName);
  604.     EndUsingLibraryResources(savedRefNum);
  605.     DisposeIText(fileName);
  606.  
  607.     SetWTitle(dlg,(StringPtr)dWinName);
  608.     ODDeleteObject(file);
  609.  
  610.     DialogPeek dlgPeek;
  611. #if no_ictb_exists
  612.     /* use the script's small font for the static text */
  613.     scriptSmallFontSize = GetScript(smSystemScript,smScriptSmallFondSize);    
  614.     TextFont(HiWord(scriptSmallFontSize));
  615.     (LoWord(scriptSmallFontSize) < tenPt) ?
  616.             TextSize(tenPt) : TextSize(LoWord(scriptSmallFontSize));
  617.     TextFace(bold);
  618.  
  619.     /* WARNING: remember to set the font, face and size for update events */
  620.     dlgPeek = (DialogPeek) dlg;
  621.     (**(dlgPeek->textH)).txFont = HiWord(scriptSmallFontSize);
  622.     if (((**(dlgPeek->textH)).txSize = LoWord(scriptSmallFontSize)) < tenPt)
  623.         (**(dlgPeek->textH)).txSize = tenPt;
  624. //    (**(dlgPeek->textH)).txFace = bold;
  625. #endif
  626.  
  627.     UserItemUPP drawBoxItemUPP; // dialogs.h
  628.     drawBoxItemUPP    = NewUserItemProc(DrawItemFrame);
  629.     
  630.     UserItemUPP drawListItemUPP = NewUserItemProc(DrawListItem);
  631.     
  632.     /* A horizontal line needs to be drawn above the list rectangle */
  633.     SetDialogItemHandle(dlg, kDraftsHorizRectUserItem, (Handle)drawBoxItemUPP);
  634.  
  635.     /* A rectangle needs to be drawn around the list column titles */
  636.     SetDialogItemHandle(dlg, kDraftsHeaderRectUserItem, (Handle)drawBoxItemUPP);
  637.  
  638.     if ( hasWriteAccess  )
  639.     {
  640.         if (prevAction == kDraftWinNone)        
  641.             SetDialogDefaultItem(dlg,kDraftsCreateBtn);
  642.         else
  643.             SetDialogDefaultItem(dlg,kDraftsDoneBtn);
  644.     }
  645.     else        // set up to draw box around create button
  646.     {
  647.         SetDialogDefaultItem(dlg,kDraftsDoneBtn);
  648.         GetDialogItem(dlg, kDraftsCreateBtn, &itemKind, &scratchHandle,
  649.                 &scratchRect);
  650.         HiliteControl( (ControlHandle)scratchHandle, 255 );    // disable create
  651.     }
  652.  
  653.     SetDialogItemHandle(dlg, kDraftsListUserItem, (Handle)drawListItemUPP);
  654.  
  655.     /* create a scrolling list of draft information */
  656.     DraftLDEFCallbackInfo hc ;
  657.     hc.dialog = dlg;
  658.     hc.dir = fDraftInfo ;
  659.     hc.stringsProc = DrawDWUserStrings ;
  660.     
  661.  
  662.     GetDialogItem(dlg, kDraftsCreatorStaticTxt, &itemKind, &scratchHandle,
  663.             &scratchRect);
  664.     hc.rectEnds[0].right = scratchRect.right;
  665.     hc.rectEnds[0].left = scratchRect.left;
  666.     GetDialogItem(dlg, kDraftsDraftStaticTxt, &itemKind, &scratchHandle,
  667.             &scratchRect);
  668.     hc.rectEnds[1].right = scratchRect.right;
  669.     hc.rectEnds[1].left = scratchRect.left;
  670.     GetDialogItem(dlg, kDraftsCreatedStaticTxt, &itemKind, &scratchHandle,
  671.             &scratchRect);
  672.     hc.rectEnds[2].right = scratchRect.right;
  673.     hc.rectEnds[2].left = scratchRect.left;
  674.     GetDialogItem(dlg, kDraftsCommentStaticTxt, &itemKind, &scratchHandle,
  675.             &scratchRect);
  676.     hc.rectEnds[3].right = scratchRect.right;
  677.     hc.rectEnds[3].left = scratchRect.left;
  678.     
  679.     GetDialogItem(dlg, kDraftsArrowStaticTxt, &itemKind, &scratchHandle,
  680.             &scratchRect);
  681.     hc.arrowEnds.right = scratchRect.right;
  682.     hc.arrowEnds.left = scratchRect.left;
  683.  
  684.     fCreateSet = (prevAction == kDraftWinNone) && hasWriteAccess;
  685.  
  686.     session->GetClipboard(ev)->SetPlatformClipboard( ev, kODNULL );
  687.  
  688.     ODSShort numLines;
  689.     ListHandle listH = fListH = this->MakeAList(dlg, &numLines, (long)&hc );
  690.     ((WindowPeek)dlg)->refCon = (long)this;
  691.     dlgPeek = (DialogPeek) dlg;
  692.     UpdateDialog( dlg,(dlgPeek->window).port.visRgn);
  693.     ShowWindow(dlg);    
  694.  
  695.     // <eeh> does this work?
  696.     LSetDrawingMode(kODTrue, listH);
  697.     
  698.     DraftWinAction dWinAction = kDraftWinNone;
  699.     ODUseCommandKeyStringsResource( kDraftsCmdKeyStrs );
  700.     ModalFilterUPP modalFilter = NewModalFilterProc(CheckDeleteKeyFilterProc);
  701.     SetButtonStates( dlg, hasWriteAccess, fDraftInfo != kODNULL );
  702.     while (dWinAction == kDraftWinNone)
  703.     {
  704. #if ODDebug
  705.         this->CheckConsistency();
  706. #endif
  707.         ODUseCommandKeyStringsResource( kDraftsCmdKeyStrs );
  708.         BeginUsingLibraryResources(savedRefNum);        // for the cmd key str#
  709.         ModalDialog( modalFilter, &itemHit );
  710.         EndUsingLibraryResources(savedRefNum);
  711.         
  712.         switch    (itemHit)
  713.         {
  714.             case kODUpArrowItem:
  715.             case kODPageUpArrowItem:
  716.             case kODHomeArrowItem:
  717.             case kODDownArrowItem:
  718.             case kODPageDownArrowItem:
  719.             case kODEndArrowItem:
  720. //                ArrowKeyScrollList( itemHit, listH, numLines,
  721. //                        this->CountDrafts()-1 );
  722.                 break;
  723.  
  724.             case kDraftsDoneBtn:
  725.                 dWinAction = kDraftWinDone;
  726.                 break;
  727.  
  728.             case kDraftsCreateBtn:
  729.                 LActivate(kODFalse,listH);
  730.                 if (this->CreateDraft(ev))
  731.                     dWinAction = kDraftWinCreate;
  732.                 LActivate(kODTrue,listH);
  733.                 ShowWindow(dlg);
  734.                 break;
  735.  
  736.             case kDraftsListUserItem:
  737.                 continue;
  738.  
  739.             case kDraftsDeleteBtn:
  740.             case kDraftsOpenBtn:
  741.                 WASSERT( fDraftInfo );
  742.                 FullDraftInfoRec* selDraftInfoRec =
  743.                         FirstSelectedRow( fDraftInfo );
  744.  
  745.                 WASSERT(selDraftInfoRec);
  746.                 ODReleaseObject(ev,fSelectedDraft);
  747.                 WASSERT(selDraftInfoRec->GetDIRType() == kDIRTypeFull);
  748.                 fSelectedDraft = selDraftInfoRec->Draft();
  749.                 fSelectedDraft->Acquire(ev);
  750.                 fSelectedDraftNumber = selDraftInfoRec->Number();
  751.  
  752.                 if    (itemHit == kDraftsDeleteBtn)
  753.                 {
  754.                     LActivate(kODFalse,listH);
  755.                     if (this->RemoveSelectedDrafts(ev))
  756.                         dWinAction = kDraftWinDelete;
  757.                     LActivate(kODTrue,listH);
  758.                     ShowWindow(dlg);
  759.                 }
  760.                 else 
  761.                 {
  762.                     dWinAction = kDraftWinOpen;
  763.                 }
  764.                 break;
  765. #ifdef _APPLEGUIDE_READY_
  766.             case kDraftsAGButtonItem:
  767.                 OpenAppleGuide( ODGetIndShort( kODShellGuideSearchIndices,
  768.                         kODShellGuideStringIndexMainDraft ) );
  769.                 break;
  770. #endif
  771.             default:
  772.                 break;
  773.         }
  774.         UpdateDialog(dlg,(dlgPeek->window).port.visRgn);
  775.     }
  776.  
  777.     if (listH != kODNULL)
  778.     {
  779.         CUsingLibraryResources r;
  780.         // Release LDEF and the UPP it points to after deleting the list:
  781.         Handle ldef = (**listH).listDefProc;
  782.         LDispose(listH);
  783.         DisposeRoutineDescriptor(
  784.                 (*(ListDefUPP*)&((*ldef)[kDraftWinLDEFAddrOffset])) );
  785.         ReleaseResource(ldef);
  786.     }
  787.  
  788.     DisposeRoutineDescriptor(modalFilter);
  789.     DisposeRoutineDescriptor(drawBoxItemUPP);
  790.     DisposeRoutineDescriptor(drawListItemUPP);
  791.     
  792.     DisposeDialog(dlg);
  793.     SetPort(savePort);
  794.     
  795.     // dispose of DraftInfoRecs and collection
  796.     ODDeleteObject(fDraftInfo);
  797.  
  798.     if (dWinAction == kDraftWinCreate)
  799.     {
  800.         ODReleaseObject(ev,fSelectedDraft);
  801.         fSelectedDraftNumber = 0;
  802.     }
  803.  
  804.     return dWinAction;
  805. }    // DraftWindow::Drafts
  806.  
  807. void    DraftWindow::DeleteSelectedDraft(Environment* ev, ODSession* session) 
  808. {
  809.     WASSERT(fSelectedDraft);
  810.     if (fSelectedDraft == fDraft) 
  811.         ; // can't delete current draft, this shouldn't happen!
  812.     else if (fSelectedDraft->GetRefCount(ev)>1)
  813.     {
  814.         // When the exceptionalert code becomes a utility, call it
  815.         // here.  That allow us to not THROW an error, which we don't
  816.         // want to do because there's no code to catch it in places
  817.         // where cleanup must be done.
  818.  
  819.         WARN( "kODErrOutstandingDraft: trying to delete open draft." );
  820.         SysBeep( 2 );
  821.     }
  822.     else 
  823.     {
  824.         ODDraft* fromDraft = 
  825.                 fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL,    /* -- TÇ: $$$$$ Don't know if this is a true leak */
  826.                 fSelectedDraft, kODPosFirstAbove,kODFalse);
  827.         ODBoolean openDraftAbove = kODFalse;
  828.         // if draft just above selected draft is open, close and open it again
  829.         // otherwise the window would be pointing to the wrong draft
  830.         ODWindowState* windowState = session->GetWindowState(ev);
  831.         if (windowState->GetRootWindowCount(ev, fromDraft)) {
  832.             ODCloseDraft(ev, session, fromDraft);
  833.             openDraftAbove = kODTrue;
  834.         }
  835.         fDocument->SaveToAPrevDraft(ev,fromDraft,fSelectedDraft);
  836.         fDocument->CollapseDrafts(ev,fromDraft,fSelectedDraft); // Releases fSelectedDraft
  837.  
  838.         // open the selected draft again, this is now what was the draft just above it
  839.         if (openDraftAbove != kODFalse)
  840.             ODOpenDraft(ev, session, fSelectedDraft);
  841.         
  842.         // rename any open window in the drafts above
  843.         TempODDraft topDraft = fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL,kODNULL,kODPosTop,kODFalse);
  844.         TempODDraft nextDraft = fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL,
  845.                         fSelectedDraft, kODPosFirstAbove,kODFalse);
  846.         while (ODObjectsAreEqual(ev, nextDraft, topDraft) == kODFalse) {
  847.             windowState->SetDefaultWindowTitles(ev, nextDraft);
  848.             nextDraft = fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL, nextDraft, kODPosFirstAbove,kODTrue);
  849.         }
  850.  
  851.         fSelectedDraft = kODNULL;
  852.         fSelectedDraftNumber = 0;
  853.     }
  854. }
  855.  
  856. //------------------------------------------------------------------------------
  857. // InternalizeHistory
  858. //------------------------------------------------------------------------------
  859.  
  860. FullDraftInfoRec* DraftWindow::InternalizeHistory(Environment* ev)
  861. {
  862.     ODDocument*        document = fDraft->GetDocument(ev);
  863.     TempODDraft        prevDraft = kODNULL;
  864.     TempODDraft        bottomDraft = document->AcquireBaseDraft(ev,kODDPReadOnly);
  865.     FullDraftInfoRec*    aDraftInfoRec;
  866.     
  867.     if (HAS_WRITE_ACCESS(fDraft->GetPermissions(ev)))
  868.     {
  869.         WASSERT(document->Exists(ev, 0, fDraft, kODPosFirstBelow));
  870.  
  871.         prevDraft =    document->AcquireDraft(ev,kODDPReadOnly,kODNULL,fDraft,
  872.                     kODPosFirstBelow,kODFalse);
  873.     }
  874.     else 
  875.     {
  876.         prevDraft = fDraft;
  877.         prevDraft->Acquire(ev);
  878.     }
  879.  
  880.     FullDraftInfoRec* firstInfoRec = kODNULL;
  881.     if ( prevDraft != bottomDraft )
  882.     {
  883.         ODULong    curDraftNumber = 1;
  884.         for ( ; ; )
  885.         {
  886.             // $$$$$ <eeh> each draft gets aquired twice: here and in InitDraftInfoRec
  887.             prevDraft = document->AcquireDraft( ev, kODDPReadOnly, kODNULL,
  888.                     prevDraft, kODPosFirstBelow, kODTrue );
  889.     
  890.             FullDraftInfoRec* newDIR = new FullDraftInfoRec;
  891.             newDIR->InitDraftInfoRec(ev, prevDraft);
  892.     
  893.             if ( firstInfoRec )
  894.             {
  895.                 aDraftInfoRec->SetNext(newDIR);
  896.                 aDraftInfoRec = newDIR;
  897.             }
  898.             else
  899.             {
  900.                 aDraftInfoRec = newDIR;
  901.                 firstInfoRec = aDraftInfoRec;
  902.             }
  903.             if ( prevDraft == bottomDraft )
  904.                 break;
  905.             ++curDraftNumber;
  906.         }
  907.     
  908.         ODScriptCode script = FontToScript( GetSysFont() );
  909.         ODLangCode lang = GetScriptVariable( script, smScriptLang );
  910.     
  911.         for (aDraftInfoRec = firstInfoRec; aDraftInfoRec!=kODNULL;
  912.                 aDraftInfoRec =
  913.                 (FullDraftInfoRec*)((DraftInfoRec*)aDraftInfoRec)->Next())
  914.         {
  915.             aDraftInfoRec->SetNumber( curDraftNumber-- );
  916.             Str255 numberStr;
  917.             NumToString( aDraftInfoRec->Number(), numberStr);
  918.             aDraftInfoRec->SetNumberString( CreateIText( script, lang, numberStr ));
  919.         }
  920.     }
  921.  
  922.     return firstInfoRec;
  923. }
  924.  
  925. void    DraftWindow::DraftSaved(Environment* ev, ODDraft* draft) 
  926. {
  927.     ODTime    savedTimeDate;
  928.     time((time_t *)(&savedTimeDate));
  929.     TempODStorageUnit    su = draft->AcquireDraftProperties(ev);
  930.     ODSetTime_TProp(ev, su, kODPropDraftSavedDate, kODTime_T, savedTimeDate);
  931. }
  932.  
  933. ODSShort    DraftWindow::CountDrafts()
  934. {
  935.     DraftInfoRec* dir = fDraftInfo;
  936.     ODSShort result;
  937.     for ( result = 0; dir; dir = dir->Next() )
  938.         if ( dir->GetDIRType() == kDIRTypeFull )
  939.             ++result;
  940.     return result;
  941. }
  942.  
  943. ODBoolean    DraftWindow::CreateDraft(Environment* ev)
  944. {
  945.     short          itemHit,itemKind;
  946.     Handle        itemHandle;
  947.     Rect        scratchRect;
  948.     DialogPtr      dlg;
  949.     Str255        aS255;
  950.     ODBoolean    result;
  951.     GrafPort*    savePort;
  952.  
  953.     TempODStorageUnit su = fDraft->AcquireDraftProperties(ev);
  954.     ODSession *session = su->GetSession(ev);
  955.  
  956.     GetPort(&savePort);
  957.     { CUsingLibraryResources r;
  958.         dlg  = ODGetNewDialog(ev,kCreateDraftsDlgID,session);
  959.     }
  960.     THROW_IF_NULL(dlg);
  961.     SetPort(dlg);
  962.  
  963. #ifdef _APPLEGUIDE_READY_
  964.     DialogSetUpAppleGuide( dlg, kCreateDraftsAGButtonItem );
  965. #endif
  966.  
  967.     SetDialogDefaultItem(dlg, kCreateDraftsCreateBtn);
  968.     SetDialogCancelItem(dlg, kCreateDraftsCancelBtn);
  969.  
  970.     GetDialogItem(dlg, kCreateDraftsNameEditTxt, &itemKind,
  971.             &itemHandle, &scratchRect);
  972.     ODIText userName;
  973.     session->GetUserName(ev, &userName);
  974.     Str255 userNamePStr ;
  975.     IntlToPStr(&userName, userNamePStr);
  976.     SetDialogItemText(itemHandle,userNamePStr);
  977.     DisposeITextStruct(userName);
  978.     
  979.     /* make the Comments edit text field active: (0, 0) = beginning of text */
  980.     SelectDialogItemText(dlg, kCreateDraftsCommentsEditTxt, 0, 0);
  981.     
  982.     /* get the draft # dynamically and add to static text… */
  983.     ODULong num = fDraftInfo?fDraftInfo->Number() + 1 : 1;
  984.     NumToString( num, aS255 );
  985.  
  986.     // This acts to replace the "^0" in static text item 8 with the
  987.     // number of the draft.  Since item 8 is the only static text item
  988.     // in the dialog we don't have to say which one.  I guess....
  989.     ParamText(aS255,"\p","\p","\p");
  990.  
  991.     DialogScriptData dsd;
  992.     ODUseDialogScriptData( &dsd, dlg );
  993.  
  994.     ShowWindow(dlg);
  995.     
  996.     ModalFilterUPP modalFilter =
  997.             NewModalFilterProc(CheckKeyScriptFirstFilterProc);
  998.  
  999.     ODUseCommandKeyStringsResource( kDraftsCreateCmdKeyStrs );
  1000.     do {
  1001.         ODSLong savedRefNum;
  1002.         BeginUsingLibraryResources(savedRefNum);        // for the cmd key str#
  1003.         ModalDialog( modalFilter, &itemHit );
  1004.  
  1005.         EndUsingLibraryResources(savedRefNum);
  1006.         switch(itemHit)
  1007.         {
  1008.             case kCreateDraftsNameEditTxt:
  1009.                 break;
  1010.             case kCreateDraftsCommentsEditTxt:
  1011.                 break;
  1012. #ifdef _APPLEGUIDE_READY_
  1013.             case kCreateDraftsAGButtonItem:
  1014.                 OpenAppleGuide( ODGetIndShort( kODShellGuideSearchIndices,
  1015.                         kODShellGuideStringIndexDraftCreate ) );
  1016.                 break;
  1017. #endif
  1018.         }
  1019.     } while ((itemHit != kCreateDraftsCreateBtn) &&
  1020.             (itemHit != kCreateDraftsCancelBtn));
  1021.  
  1022.     DisposeRoutineDescriptor(modalFilter);
  1023.  
  1024.     result = (itemHit == kCreateDraftsCreateBtn);
  1025.     if (result)
  1026.     {
  1027.         Str255 aStr255;
  1028.         
  1029.     // update Name
  1030.         GetDialogItem(dlg, kCreateDraftsNameEditTxt, &itemHit,
  1031.                 &itemHandle, &scratchRect);
  1032.         GetDialogItemText(itemHandle,aStr255);
  1033.         TempODIText name = CreateIText( dsd.Script(), dsd.Language(),
  1034.                 (StringPtr)aStr255 );
  1035.         ODSetITextProp( ev, su, kODPropModUser, kODMacIText, name);
  1036.  
  1037.     // update Comments.  Note that it's now possible to display long ones
  1038.     // and that therefore we want to allow them bigger than 255.
  1039.         GetDialogItem(dlg, kCreateDraftsCommentsEditTxt, &itemHit, &itemHandle,
  1040.                 &scratchRect);
  1041.         ODSize strLen = GetHandleSize(itemHandle);
  1042.         TempODIText comments = CreateIText( dsd.Script(), dsd.Language(),
  1043.                 (ODUByte*)*itemHandle, strLen );
  1044.         ODSetITextProp( ev, su, kODPropDraftComment, kODMacIText, comments);
  1045.     }
  1046.     DisposeDialog(dlg);
  1047.     SetPort(savePort);
  1048.     return result;
  1049. }    // CreateDraft()
  1050.  
  1051.  
  1052. ODBoolean    DraftWindow::RemoveSelectedDrafts(Environment* ev)
  1053. {
  1054.     short          itemHit;
  1055.     DialogPtr      dlg;
  1056.     Str255        aS255,aS2552;
  1057.     GrafPort*    savePort;
  1058.  
  1059.     GetPort(&savePort);
  1060.     {    
  1061.         TempODStorageUnit draftProps = fDraft->AcquireDraftProperties(ev);
  1062.         ODSession *session = draftProps->GetSession(ev);
  1063.         CUsingLibraryResources r;
  1064.         dlg = ODGetNewDialog( ev, kDeleteDraftsDlogID, session );
  1065.     }
  1066.     THROW_IF_NULL(dlg);
  1067.     SetPort(dlg);
  1068.  
  1069.     SetDialogDefaultItem(dlg, kDeleteDraftsCancelBtn);
  1070.     SetDialogCancelItem(dlg, kDeleteDraftsCancelBtn);
  1071.  
  1072.     PlatformFile* file = GetPlatformFileFromContainer(ev,
  1073.             fDraft->GetDocument(ev)->GetContainer(ev));
  1074.  
  1075.     file->GetAsciiName((char*)aS255,255);
  1076.     ODDeleteObject(file);
  1077.     CToPascalString((char*)aS255);
  1078.     NumToString( fSelectedDraftNumber, aS2552 );
  1079.     ParamText(aS2552,aS255,"\p","\p");
  1080.  
  1081.     ShowWindow(dlg);
  1082.     ModalFilterUPP modalFilter = NewModalFilterProc( CheckDeleteKeyFilterProc );
  1083.     
  1084.     do {
  1085.         ODSLong savedRefNum;
  1086.         BeginUsingLibraryResources(savedRefNum);    // for the cmd key str#
  1087.         ModalDialog( modalFilter, &itemHit );
  1088.         EndUsingLibraryResources(savedRefNum);
  1089.     } while ((itemHit != kDeleteDraftsCancelBtn) &&
  1090.             (itemHit != kDeleteDraftsDeleteBtn));
  1091.     
  1092.     DisposeRoutineDescriptor(modalFilter);
  1093.     DisposeDialog(dlg);
  1094.     SetPort(savePort);
  1095.  
  1096.     return itemHit == kDeleteDraftsDeleteBtn;
  1097. }
  1098.  
  1099. void DraftWindow::SetHilite( DraftInfoRec* from, short whichRow )
  1100. {
  1101.     if ( fHilitedRow != kODNULL )
  1102.         SetRows( fHilitedRow, 0, kODFalse, fListH );
  1103.     SetRows( from, whichRow, kODTrue, fListH );
  1104.     fHilitedRow = (FullDraftInfoRec*)GetNthRow( from, whichRow );
  1105. }
  1106.  
  1107. void    DraftWindow::Print()
  1108. {
  1109. }
  1110.  
  1111. //==============================================================================
  1112. // DraftInfoRec
  1113. //==============================================================================
  1114.  
  1115. DraftInfoRec::DraftInfoRec()
  1116. {
  1117.     fDIRType            = kDIRTypeUnknown;
  1118. //    fFirst                = kODNULL;
  1119.     fNext                 = kODNULL;
  1120.     fComment            = kODNULL;
  1121. }
  1122.  
  1123. //==============================================================================
  1124. // DummyDraftInfoRec
  1125. //==============================================================================
  1126.  
  1127. DummyDraftInfoRec::DummyDraftInfoRec()
  1128. {
  1129.     this->SetDIRType( kDIRTypeDummy );
  1130.     this->SetShouldHilite( kODFalse );
  1131.  
  1132. //    fPartialComment = kODNULL;
  1133.     fCommentOwner    = kODNULL;
  1134. }
  1135.  
  1136. //==============================================================================
  1137. // FullDraftInfoRec
  1138. //==============================================================================
  1139.  
  1140. //------------------------------------------------------------------------------
  1141. // Creation
  1142. //------------------------------------------------------------------------------
  1143.  
  1144. FullDraftInfoRec::FullDraftInfoRec()
  1145. {
  1146.     this->SetDIRType( kDIRTypeFull );
  1147.     this->SetShouldHilite( kODFalse );
  1148.  
  1149.     fDraft                 = kODNULL;
  1150.     fDraftProperties    = kODNULL;
  1151.     fDraftID             = kODNULL;
  1152.     fDraftNumber         = 0;
  1153.     fDraftNumberString    = kODNULL;
  1154.     fSaved                = kODNULL;
  1155.     fSavedString        = kODNULL;
  1156.     fCachedComment        = kODNULL;
  1157.     fModifiedBy            = kODNULL;
  1158.     fCanExpand            = kODFalse;
  1159. }
  1160.  
  1161. void FullDraftInfoRec::InitDraftInfoRec(Environment* ev, ODDraft* draft )
  1162. {    
  1163.     draft->Acquire(ev);
  1164.     fDraft = draft;
  1165.     fDraftProperties = draft->AcquireDraftProperties(ev);
  1166.     fDraftID = draft->GetID(ev);
  1167.  
  1168.     fModifiedBy = ODGetITextProp( ev, fDraftProperties,
  1169.                         kODPropModUser, kODMacIText, kODNULL);
  1170.  
  1171.     fSaved = ODGetTime_TProp(ev, fDraftProperties, kODPropDraftSavedDate,
  1172.             kODTime_T);
  1173.  
  1174.     Str255 dateString;
  1175.     IUDateString( fSaved, shortDate, dateString );
  1176.     Str255 timeString;
  1177.     IUTimeString( fSaved, kODFalse, timeString );
  1178.     
  1179.     Str255 dateTimeString;
  1180.     ODSLong savedRefNum;
  1181.     BeginUsingLibraryResources(savedRefNum);
  1182.     ReplaceIntoString( kDraftsWnDateSpaceResID, dateString,
  1183.             timeString, dateTimeString );
  1184.     EndUsingLibraryResources(savedRefNum);
  1185.     ODScriptCode script = GetScriptManagerVariable(smSysScript);
  1186.     ODLangCode lang = GetScriptVariable(script, smScriptLang);
  1187.     fSavedString = CreateIText( script, lang, dateTimeString );
  1188.  
  1189.     ODIText* comment = ODGetITextProp( ev, fDraftProperties,
  1190.                         kODPropDraftComment, kODMacIText, kODNULL );
  1191.     WASSERT( comment );
  1192.     this->SetComment( comment );
  1193. }
  1194.  
  1195.  
  1196. //------------------------------------------------------------------------------
  1197. // Destruction
  1198. //------------------------------------------------------------------------------
  1199.  
  1200. DraftInfoRec::~DraftInfoRec()
  1201. {
  1202.     ODDeleteObject(fNext);
  1203.     DisposeIText(fComment);
  1204. }
  1205.  
  1206. #if ODDebug
  1207. DummyDraftInfoRec::~DummyDraftInfoRec()
  1208. {
  1209.     WASSERT( this->GetDIRType() == kDIRTypeDummy);
  1210. }
  1211. #endif
  1212.  
  1213. FullDraftInfoRec::~FullDraftInfoRec()
  1214. {
  1215.     WASSERT( this->GetDIRType() == kDIRTypeFull);
  1216.     Environment* ev = somGetGlobalEnvironment();
  1217.     
  1218.     ODReleaseObject(ev,fDraftProperties);
  1219.     ODReleaseObject(ev,fDraft);
  1220.     
  1221.     DisposeIText(fDraftNumberString);
  1222.     DisposeIText(fSavedString);
  1223.     DisposeIText(fModifiedBy);
  1224.     DisposeIText(fCachedComment);
  1225. }
  1226.  
  1227. //------------------------------------------------------------------------------
  1228. // filter procs
  1229. //------------------------------------------------------------------------------
  1230.  
  1231. static pascal ODBoolean DraftDlgFilterProc( DialogPtr dialog, EventRecord *event,
  1232.         short *itemHit )
  1233. {    
  1234.     Rect        itemRect;
  1235.     short        itemType;
  1236.     Handle        itemHandle;
  1237.     long refcon = ((WindowPeek)dialog)->refCon;
  1238.     DraftWindow* self = (DraftWindow*)refcon;
  1239.     ListHandle listH = self->GetListHandle();
  1240.     ODBoolean result = kODFalse;
  1241.  
  1242.     if (event->what == mouseUp)
  1243.     {
  1244.         if ( READYTOCLOSESET( refcon ) )
  1245.         {
  1246.             *itemHit = kDraftsOpenBtn;
  1247.             result = kODTrue;
  1248.         }
  1249.     }
  1250.     else if (event->what == mouseDown)
  1251.     {
  1252.         GetDialogItem(dialog, kDraftsListUserItem, &itemType, &itemHandle, &itemRect);
  1253.         Point mpt = event->where;
  1254.         SetPort(dialog);
  1255.         GlobalToLocal(&mpt);
  1256.         if ( PtInRect(mpt, &itemRect) )
  1257.         {
  1258.             if ( LClick( mpt, event->modifiers, listH ) )
  1259.             {
  1260.                 WASSERT( !READYTOCLOSESET( refcon ) );
  1261.                 SETREADYTOCLOSE( refcon );
  1262.             }
  1263.             else if ( self->ProcessMousedownInList( dialog, listH, mpt ) )
  1264.                 InvalRect( &itemRect );
  1265.             *itemHit = kDraftsListUserItem;
  1266.             result = kODTrue;
  1267.         }
  1268.     }
  1269.     // <eeh> autoKey too?
  1270.     else if ( (event->what == keyDown) && !CREATEISSET(refcon) )
  1271.     {
  1272.         // the "done" button is shown as the default though it is item
  1273.         // #2, so we need to override the ODArrowKeyFilterProc's behavior.
  1274.         char key = event->message & charCodeMask;
  1275.         if ( (key == kEnterKey) || (key ==kReturnKey) )
  1276.         {
  1277.             FlashButtonItem( dialog, kDraftsDoneBtn );
  1278.             *itemHit = kDraftsDoneBtn;
  1279.             result = kODTrue;
  1280.         }
  1281.     }
  1282.  
  1283.     return result || ODArrowKeyFilterProc( dialog, event, itemHit );
  1284. }
  1285.  
  1286. static pascal ODBoolean CheckKeyScriptFirstFilterProc( DialogPtr dialog,
  1287.         EventRecord *event, short *itemHit)
  1288. {
  1289.     // pass to the next filter proc.  This one just changes state, never
  1290.     // consuming the event.
  1291.     return CheckKeyScriptChangeFilterProc( dialog, event, itemHit )
  1292.             || ODButtonKeyFilterProc( dialog, event, itemHit );
  1293. }
  1294.  
  1295. static DraftInfoRec* GetNthRow( DraftInfoRec* from, short whichRow )
  1296. {
  1297.     WASSERT( from );
  1298.     WASSERT( whichRow >= 0 );
  1299.     while ( whichRow-- )
  1300.     {
  1301.         from = from->Next();
  1302.         WASSERT( from );
  1303.     }
  1304.     return from;
  1305. }
  1306.  
  1307. static void SetRows( DraftInfoRec* dir,    short startRow, ODBoolean newValue,
  1308.         ListHandle listH )
  1309. {
  1310.     dir = GetNthRow( dir, startRow );
  1311.     WASSERT(dir);
  1312.     WASSERT( dir->GetDIRType() == kDIRTypeFull );
  1313.     dir->SetShouldHilite( newValue );
  1314.     Cell cell;
  1315.     cell.h = 0;
  1316.     cell.v = startRow;
  1317.     while ( ((dir = dir->Next()) != NULL) && dir->GetDIRType() == kDIRTypeDummy )
  1318.     {
  1319.         dir->SetShouldHilite( newValue );
  1320.         ++cell.v;
  1321.     }
  1322. }
  1323.  
  1324. static FullDraftInfoRec* FirstSelectedRow( DraftInfoRec* from )
  1325. {
  1326.     while ( from && !from->ShouldHilite() )
  1327.         from = (FullDraftInfoRec*)from->Next();
  1328.  
  1329.     WASSERT( from );
  1330.     WASSERT( from->GetDIRType() == kDIRTypeFull );
  1331.     return (FullDraftInfoRec*)from;
  1332. }
  1333.  
  1334. static pascal void DrawListItem(DialogPtr dlog, short theItem)
  1335. {
  1336.     LUpdate(dlog->visRgn, GETLISTHANDLE(((WindowPeek)dlog)->refCon));
  1337.     Rect listRect;
  1338.     GETLISTRECT( ((WindowPeek)dlog)->refCon, &listRect );
  1339.     FrameRect( &listRect );
  1340. }
  1341.  
  1342. static void ContractList( FullDraftInfoRec* dir, ListHandle listH,    short parentRowNum )
  1343. {
  1344.     WASSERT( dir );
  1345.     WASSERT( dir->GetDIRType() == kDIRTypeFull );
  1346.  
  1347.     DisposeIText( dir->GetComment() );
  1348.     dir->UncacheComment();
  1349.  
  1350.     // Patch around the dummy entries and dispose them.  Remember that
  1351.     // ~DraftInfoRec deletes fNext recursively, so clip the list free
  1352.     // at both ends before deleting.
  1353.  
  1354.     DummyDraftInfoRec* findNextFull = (DummyDraftInfoRec*)dir->Next();
  1355.     WASSERT(findNextFull);
  1356.     DummyDraftInfoRec* rememberPrev = kODNULL;
  1357.     short removedCount = 0;
  1358.     while ( findNextFull && (findNextFull->GetDIRType() != kDIRTypeFull) )
  1359.     {
  1360.         rememberPrev = findNextFull;
  1361.         findNextFull = (DummyDraftInfoRec*)findNextFull->Next();
  1362.         ++removedCount;
  1363.     }
  1364.     WASSERT( rememberPrev );
  1365.     rememberPrev->SetNext( kODNULL );
  1366.     delete dir->Next();        // this is the head of the list
  1367.  
  1368.     dir->SetNext( findNextFull );
  1369.     
  1370.     LDelRow( removedCount, parentRowNum, listH );
  1371. }
  1372.  
  1373. static TEHandle ITextToTERec( ODIText* iText, Rect* bothRects )
  1374. {
  1375.     TEHandle hTE = TENew( bothRects, bothRects );
  1376.  
  1377.     short newFont = GetScriptVariable( GetITextScriptCode(iText),
  1378.             smScriptAppFond );
  1379.     (*hTE)->txFont = newFont;
  1380.     TESetText( GetITextPtr( iText ), GetITextStringLength(iText), hTE );
  1381.     return hTE;
  1382. }
  1383.  
  1384. static void ExpandList( FullDraftInfoRec* dir, ListHandle listH, DialogPtr dialog,
  1385.         short parentRowNum )
  1386. {
  1387.     WASSERT(dir);
  1388.     WASSERT(dir->GetDIRType() == kDIRTypeFull);
  1389.     
  1390.     // Get the text of the comment, figure out how many lines it'll require
  1391.     // not truncated, and create dummy DraftInfoRecs each of them holding
  1392.     // one line.  TE will calculate line breaks based on a rect given,
  1393.     // so use the left and right fields from the comments column.
  1394.     // REMEMBER that the first line goes in the existing "parent" entry.
  1395.     
  1396.     Rect itemRect;
  1397.     short ignoreType;
  1398.     Handle ignoreHandle;
  1399.     GetDialogItem( dialog, kDraftsCommentStaticTxt, &ignoreType, &ignoreHandle,
  1400.             &itemRect );
  1401.     itemRect.top = 0;
  1402.     itemRect.bottom = 0x7fff;        // why be shy?
  1403.     itemRect.right -= 1;            // make TE linewrap same as our trunc function
  1404.     
  1405.     ODIText* iText = dir->GetComment();
  1406.     // save off the truncatable comment for when we're contracted
  1407.     dir->CacheComment();
  1408.     
  1409.     TEHandle teh = ITextToTERec( iText, &itemRect );
  1410.  
  1411.     HLock( (Handle)teh );
  1412.     HLock( (*teh)->hText );
  1413.     char* currentLine = *(*teh)->hText;
  1414.     short* curLineStart = (*teh)->lineStarts;
  1415.     WASSERT( *curLineStart == 0 );
  1416.     ODScriptCode script = GetITextScriptCode( iText );
  1417.     ODLangCode lang = GetITextLangCode( iText );
  1418.     
  1419.     FullDraftInfoRec* savedNext = (FullDraftInfoRec*)dir->Next();
  1420.     DraftInfoRec* currentParent = dir;
  1421.     ODBoolean hiliteState = dir->ShouldHilite();
  1422.     
  1423.     short numLines = (*teh)->nLines;
  1424.     LSetDrawingMode(kODFalse, listH);                                    /* turn list drawing off */
  1425.     AddRows( listH, parentRowNum, numLines-1 );
  1426.     LSetDrawingMode(kODTrue, listH);                                    /* turn list drawing off */
  1427.     for ( short i = 0 ;i < numLines; ++i )
  1428.     {
  1429.         ODUByte* thisLine = (ODUByte*)¤tLine[*curLineStart++];
  1430.         ODUByte* nextLine = (ODUByte*)¤tLine[*curLineStart];
  1431.         ODSize len = nextLine - thisLine;
  1432.         ODIText* partialComment = CreateIText( script, lang, thisLine, len );
  1433.  
  1434.         if ( i == 0 )
  1435.         {
  1436.             dir->SetComment( partialComment );
  1437.         }
  1438.         else
  1439.         {
  1440.             DummyDraftInfoRec* newDummy = new DummyDraftInfoRec;
  1441.             newDummy->SetComment( partialComment );
  1442.             newDummy->SetCommentOwner( dir );
  1443.             newDummy->SetShouldHilite( hiliteState );
  1444.             
  1445.             currentParent->SetNext(newDummy);
  1446.             currentParent = newDummy;
  1447.         }
  1448.     }
  1449.     
  1450.     TEDispose( teh );
  1451.     currentParent->SetNext(savedNext);
  1452. }
  1453.  
  1454. ODBoolean DraftWindow::ProcessMousedownInList( DialogPtr dialog,
  1455.         ListHandle listH, Point mpt )
  1456. {
  1457.     // get last cell clicked in, but
  1458.     // ignore it if the cell doesn't exist (why is this necessary?)
  1459.     Cell lastClick = LLastClick( listH );
  1460.     if ( (lastClick.v) == -1 ||
  1461.             (lastClick.v >= (*listH)->dataBounds.bottom) )
  1462.         return kODFalse;
  1463.  
  1464.     ODBoolean result = kODFalse;
  1465.  
  1466.     DraftInfoRec* dir = GetNthRow( fDraftInfo, lastClick.v );
  1467.     WASSERT( dir );
  1468.  
  1469.     if ( dir->GetDIRType() == kDIRTypeDummy )
  1470.     {
  1471.         DraftInfoRec* parent =
  1472.                 ((DummyDraftInfoRec*)dir)->GetCommentOwner();
  1473.         ODBoolean isHilited = dir->ShouldHilite();
  1474.         WASSERT( isHilited == parent->ShouldHilite() );
  1475.         if ( !isHilited )
  1476.         {
  1477.             this->SetHilite( parent, 0 );
  1478.             result = kODTrue;
  1479.         }
  1480.         return result;
  1481.     }
  1482.  
  1483.     Rect scratchRect;
  1484.     short itemType;
  1485.     Handle ignore;
  1486.     GetDialogItem(dialog, kDraftsArrowStaticTxt, &itemType,
  1487.             &ignore, &scratchRect);
  1488.     ODBoolean inGrowColumn = (mpt.h > scratchRect.left)
  1489.             && (mpt.h < scratchRect.right);
  1490.     
  1491.     if ( inGrowColumn && ((FullDraftInfoRec*)dir)->CanExpand() )
  1492.     {
  1493.         if ( ((FullDraftInfoRec*)dir)->IsExpanded() )
  1494.             ContractList( (FullDraftInfoRec*)dir, listH, lastClick.v );
  1495.         else
  1496.             ExpandList( (FullDraftInfoRec*)dir, listH, dialog, lastClick.v );
  1497.         result = kODTrue;
  1498.     }
  1499.     else if ( !dir->ShouldHilite() )
  1500.     {
  1501.         this->SetHilite( dir, 0 );
  1502.         result = kODTrue;
  1503.     }
  1504.     return result;
  1505. }
  1506.  
  1507.  
  1508. static pascal ODBoolean CheckDeleteKeyFilterProc( DialogPtr dialog, EventRecord *event,
  1509.         short *itemHit)
  1510. {
  1511.     ODBoolean result = kODFalse;
  1512.     ODBoolean isDraftsDlog = ((WindowPeek)dialog)->refCon != 0;
  1513.  
  1514.     if (event->what == keyDown)
  1515.     {
  1516.         const char kDeleteButton = 0x08;
  1517.         char key = event->message & charCodeMask;
  1518.         if ( key == kDeleteButton )
  1519.         {
  1520.             if ( isDraftsDlog )
  1521.             {
  1522.                 *itemHit = kDraftsDeleteBtn;
  1523.                 result = kODTrue;
  1524.             }
  1525.             else
  1526.             {
  1527.                 *itemHit = kDeleteDraftsDeleteBtn;
  1528.                 result = kODTrue;
  1529.             }
  1530.         }
  1531.     }
  1532.     if ( result )
  1533.         FlashButtonItem( dialog, *itemHit );
  1534.     else
  1535.     {
  1536.         if ( isDraftsDlog )
  1537.             result = DraftDlgFilterProc( dialog, event, itemHit );
  1538.         else
  1539.             result = ODDialogFilterProc( dialog, event, itemHit );
  1540.     }
  1541.  
  1542.     return result;
  1543. }
  1544.  
  1545. static void SetButtonStates( DialogPtr dlog, ODBoolean hasWriteAccess,
  1546.         Boolean hasContent )
  1547. {
  1548.     short openHiliteState = hasContent? kDraftsActiveControl : 255;
  1549.     short deleteHiliteState
  1550.             = hasContent && hasWriteAccess? kDraftsActiveControl : 255;
  1551.  
  1552.     short ignoreT;
  1553.     ControlHandle control;
  1554.     Rect ignoreR;
  1555.  
  1556.     GetDialogItem( dlog, kDraftsDeleteBtn, &ignoreT,
  1557.             (Handle*)&control, &ignoreR );
  1558.     HiliteControl( control, deleteHiliteState);
  1559.     SetControlReference( control, deleteHiliteState );
  1560.  
  1561.     GetDialogItem( dlog, kDraftsOpenBtn, &ignoreT, (Handle*)&control,
  1562.             &ignoreR );
  1563.     HiliteControl( control, openHiliteState );
  1564.     SetControlReference( control, openHiliteState );
  1565. }
  1566.  
  1567. static void AddRows( ListHandle listH, short startIndex, short numToAdd )
  1568. {
  1569.     char aByte = 'a' ;
  1570.     Cell newCell;
  1571.     newCell.h = 0;
  1572.     short finalIndex = startIndex + numToAdd;
  1573.     while ( startIndex < finalIndex )
  1574.     {
  1575.         LAddRow(1, startIndex, listH);
  1576.         newCell.v = startIndex++;
  1577.         LSetCell( &aByte, 1, newCell, listH );
  1578.     }
  1579. }
  1580.  
  1581. //------------------------------------------------------------------------------
  1582. // Callback to let LDEF communicate with DraftWindow
  1583. //------------------------------------------------------------------------------
  1584.  
  1585. void DrawDWUserStrings( struct DraftLDEFCallbackInfo *callbackInfo,
  1586.         ODSShort row, const Rect* listItemRect)
  1587. {
  1588.     DraftInfoRec *dir = callbackInfo->dir ;
  1589.     WASSERT(dir);
  1590.  
  1591.     TRY    // much of what follows can't throw, but some of it can, so I'm
  1592.         // making this thing cover nearly all of the routine.  The overhead
  1593.         // is paid but once anyway.
  1594.  
  1595.         dir = GetNthRow( dir, row );
  1596.         WASSERT( dir );
  1597.     
  1598.         DialogPtr dlog = callbackInfo->dialog;
  1599.         Rect localRect;
  1600.         localRect.top = listItemRect->top;
  1601.         localRect.bottom = listItemRect->bottom;
  1602.         
  1603.         ODIText* fourStrings[kNumColumns];
  1604.         fourStrings[kCommentsColumnIndex] = dir->GetComment();
  1605.         ODBoolean isFullType = dir->GetDIRType() == kDIRTypeFull;
  1606.         if ( isFullType )
  1607.         {
  1608.             fourStrings[0] = ((FullDraftInfoRec*)dir)->GetModifiedBy();
  1609.             fourStrings[1] = ((FullDraftInfoRec*)dir)->GetNumberString();
  1610.             fourStrings[2] = ((FullDraftInfoRec*)dir)->GetCreated();
  1611.         }
  1612.         else
  1613.         {
  1614.             WASSERT(dir->GetDIRType() == kDIRTypeDummy);
  1615.             fourStrings[0] = fourStrings[1] = fourStrings[2] = kODNULL;
  1616.         }
  1617.     
  1618.         // Determination whether a comment is too long to be drawn in a single
  1619.         // line is done lazily: it's put off until now, where the DrawITextInDlogBox
  1620.         // function get the necessary information as part of its job.  So now, in
  1621.         // addition to drawing the strings, we need to save off that information.
  1622.     
  1623.         ODBoolean truncatedThisComment = kODFalse;        // default values
  1624.         ODBoolean mayWantToTruncate;
  1625.         for ( short index = 0; index < kNumColumns; ++index )
  1626.         {
  1627.             localRect.left = callbackInfo->rectEnds[index].left;
  1628.             localRect.right = callbackInfo->rectEnds[index].right;
  1629.             if ( fourStrings[index] )
  1630.             {
  1631.                 // don't try to truncate if guaranteed short enough already.  This fixes
  1632.                 // TextEdit's ignoring of training spaces when calculating line breaks.
  1633.                 // If this is a dummy record, we *know* that the comment will fit; otherwise
  1634.                 // check if this is an expanded full record's comments column, in which
  1635.                 // case we've already clipped the comments to fit.
  1636.                 mayWantToTruncate = isFullType &&
  1637.                         ((index != kCommentsColumnIndex)
  1638.                         || !(((FullDraftInfoRec*)dir)->IsExpanded()));
  1639.                 ODBoolean truncatedThisColumn =
  1640.                         DrawITextInDlogBox( fourStrings[index],
  1641.                         &localRect, dlog, mayWantToTruncate );
  1642.                 if ( index == kCommentsColumnIndex )
  1643.                     truncatedThisComment =
  1644.                             truncatedThisComment || truncatedThisColumn;
  1645.             }
  1646.         }
  1647.         if ( truncatedThisComment )
  1648.         {
  1649.             WASSERT( dir->GetDIRType() == kDIRTypeFull );
  1650.             WASSERT( ((FullDraftInfoRec*)dir)->IsExpanded() == kODFalse );
  1651.             // record that this entry has a too-long comment
  1652.             ((FullDraftInfoRec*)dir)->SetCanExpand();
  1653.         }
  1654.     
  1655.         // now decide whether we need to draw the expansion icon and draw
  1656.         // the right one.
  1657.         
  1658.         if ( isFullType && ((FullDraftInfoRec*)dir)->CanExpand() )
  1659.         {
  1660.             localRect.left = callbackInfo->arrowEnds.left;
  1661.             localRect.right = callbackInfo->arrowEnds.right;
  1662.     
  1663.             ODSLong savedRefNum;
  1664.             BeginUsingLibraryResources(savedRefNum);        
  1665.             OSErr err = PlotIconID( &localRect, atNone, ttNone,
  1666.                     ((FullDraftInfoRec*)dir)->IsExpanded() ?
  1667.                     kDWOpenTriangleResID : kDWClosedTriangleResID );
  1668.             EndUsingLibraryResources(savedRefNum);
  1669.         }
  1670.  
  1671.         // finally, hilite if this record is [part of] the selection
  1672.         if ( dir->ShouldHilite() )
  1673.         {
  1674.             short oldPenMode = dlog->pnMode;
  1675.             PenMode( hilitetransfermode );
  1676.             PaintRect( listItemRect ) ;
  1677.             PenMode( oldPenMode );
  1678.         }
  1679.  
  1680.     CATCH_ALL
  1681.         WARN( "ignoring error in DrawDWUserStrings" );
  1682.     ENDTRY
  1683. }
  1684.  
  1685.  
  1686.  
  1687.  
  1688.